#include "myTasks.h"
#include "rtx.h"
#include "cmdProcess.h"
#include "segment_LED.h"

#define LED_ON          0
#define LED_OFF         1

#define LED_BLINK_ON    1
#define LED_BLINK_OFF   0

#define LED_R(x)        HAL_GPIO_WritePin(GPIOA, GPIO_PIN_6, x)
#define LED_G(x)        HAL_GPIO_WritePin(GPIOA, GPIO_PIN_15, x)
#define LED_B(x)        HAL_GPIO_WritePin(GPIOA, GPIO_PIN_7, x)

#define LED_B_BLINK(x)  do{\
                            if(x){\
                                rtx_Timer_add(&task_blink.timer);\
                            }else {\
                                rtx_Timer_remove(&task_blink.timer);\
                            }\
                        }while(0)


void task_func_heart_beat(void *param);
void task_func_cmd(void *param);
void task_func_blink(void *param);
void task_func_num_flow(void *param);
void subscriber_cb_tester(void *param);
void alarm_cb_tester(void *param);
void subscriber_cb_sleep(void *param);
void alarm_cb_sleep(void *param);


// 心拍周期任务对象
struct mt_Task_stu task_heart_beat = {
    .topic = {
        .flag = 0,
        .subscriber = NULL,

        .next = NULL,
    },

    .timer = {
        .tick_counts = 1000,
        .tick_reload = 1000,

        .topic = &(task_heart_beat.topic),
        .next = NULL,
    },

    .subscriber = {
        .callback_func = task_func_heart_beat,

        .next = NULL,
    },
};


// 命令处理周期任务对象
struct mt_Task_stu task_cmd = {
    .topic = {
        .flag = 0,
        .subscriber = NULL,

        .next = NULL,
    },

    .timer = {
        .tick_counts = 200,
        .tick_reload = 200,

        .topic = &(task_cmd.topic),
        .next = NULL,
    },

    .subscriber = {
        .callback_func = task_func_cmd,

        .next = NULL,
    },
};


// 蓝灯闪烁周期任务对象
struct mt_Task_stu task_blink = {
    .topic = {
        .flag = 0,
        .subscriber = NULL,

        .next = NULL,
    },

    .timer = {
        .tick_counts = 100,
        .tick_reload = 100,

        .topic = &(task_blink.topic),
        .next = NULL,
    },

    .subscriber = {
        .callback_func = task_func_blink,

        .next = NULL,
    },
};


// 实时反应时间显示周期任务对象
struct mt_Task_stu task_num_flow = {
    .topic = {
        .flag = 0,
        .subscriber = NULL,

        .next = NULL,
    },

    .timer = {
        .tick_counts = 1,
        .tick_reload = 1,

        .topic = &(task_num_flow.topic),
        .next = NULL,
    },

    .subscriber = {
        .callback_func = task_func_num_flow,

        .next = NULL,
    },
};


// 反应测试相关内容
struct rtx_Topic_stu topic_tester = {
    .flag = 0,
    .subscriber = NULL,

    .next = NULL,
};

struct rtx_Topic_subscriber_stu subscriber_tester = {
    .callback_func = subscriber_cb_tester,

    .next = NULL,
};

struct rtx_Alarm_stu alarm_tester = {
    .flag = 0,
    .tick_count_down = 0,

    .callback_alarm = alarm_cb_tester,

    .next = NULL,
};

struct reaction_tester_stu tester = {
    .triger_ms = 0,

    .click_ms = 0,
    .click_us = 0,

    .flag_last_pin_state = 1,
};


// 自动休眠相关内容
struct rtx_Topic_subscriber_stu subscriber_sleep = {
    .callback_func = subscriber_cb_sleep,

    .next = NULL,
};

struct rtx_Alarm_stu alarm_sleep = {
    .flag = 0,
    .tick_count_down = 0,

    .callback_alarm = alarm_cb_sleep,

    .next = NULL,
};



// 添加周期任务 API
int mt_Task_add(struct mt_Task_stu *task){
    rtx_Topic_add(&(task->topic));
    rtx_Topic_subscribe(&(task->topic), &(task->subscriber));
    rtx_Timer_add(&(task->timer));

    return 0;
}

// -----------------初始化自定义任务----------------
int myTask_init(void){
    // 创建心拍周期任务
    mt_Task_add(&task_heart_beat);

    // 创建命令处理周期任务
    mt_Task_add(&task_cmd);

    // 创建蓝灯闪烁周期任务
    mt_Task_add(&task_blink);
    // 默认关闭
    LED_B_BLINK(LED_BLINK_OFF);

    // 创建反应时间显示周期任务
    mt_Task_add(&task_num_flow);
    // 默认关闭task_num_flow
    rtx_Timer_remove(&task_num_flow.timer);

    // 注册反应测试相关内容
    rtx_Topic_add(&topic_tester);
    rtx_Topic_subscribe(&topic_tester, &subscriber_tester);

    // 注册自动休眠相关内容
    rtx_Topic_subscribe(&topic_tester, &subscriber_sleep);
    rtx_Alarm_set_count(&alarm_sleep, 30000);
    rtx_Alarm_add(&alarm_sleep);

    
    LED_G(LED_OFF);
    LED_B(LED_ON);
    LED_R(LED_OFF);

    return 0;
}


// 心拍任务
uint32_t heart_beat_count = 0;
void task_func_heart_beat(void *param){

    heart_beat_count ++;
    // LOG_FMT("Heartbeat: %d\n", heart_beat_count);

    // static uint8_t i = 5;
    // SEG_LED_show_num(&mySegLED, i);
    // i = (i+1)%SEG_LED_NUM_MAX;
}


uint8_t cmd_buffer[CMD_BUF_SIZE];
// 处理命令任务
void task_func_cmd(void *param){

    // 读取命令
    if(SEGGER_RTT_HasData(0)){
        int len = SEGGER_RTT_Read(0, cmd_buffer, CMD_BUF_SIZE - 1);
        if (len > 0) {
            cmd_buffer[len] = '\0'; // 添加字符串终止符
            for(uint8_t i = len - 1; i > 0; i --){ // 去除尾追回车
                if(cmd_buffer[i] == '\n' || cmd_buffer[i] == '\r'){
                    cmd_buffer[i] = 0;
                }else {
                    break;
                }
            }

            // LOG_FMT(PRINT_DEBUG"cmd len: %d\n", len);
            cmd_process((char *)cmd_buffer); // 处理命令
        }
    }
}


// 蓝灯闪烁任务
void task_func_blink(void *param){
    static uint8_t led_b_state = 0;
    led_b_state = !led_b_state;
    LED_B(led_b_state);
    // LOG_STR(PRINT_DEBUG"B\n");
}


// 实时反应时间显示任务
void task_func_num_flow(void *param){
    TickType_t now_ms = rtx_Sys_get_tick() - tester.triger_ms;
    my_lcd_clean_all();
        if(now_ms < 10){
            SEG_LED_show_num(lcd_p[0], now_ms%10);
        }else if(now_ms < 100){
            SEG_LED_show_num(lcd_p[0], (now_ms/10)%10);
            SEG_LED_show_num(lcd_p[1], now_ms%10);
        }else if(now_ms < 1000){
            SEG_LED_show_num(lcd_p[0], (now_ms/100)%10);
            SEG_LED_show_num(lcd_p[1], (now_ms/10)%10);
            SEG_LED_show_num(lcd_p[2], now_ms%10);
        }else {
            SEG_LED_show_num(lcd_p[0], now_ms/1000);
            SEG_LED_show_num(lcd_p[1], (now_ms/100)%10);
            SEG_LED_show_num(lcd_p[2], (now_ms/10)%10);
            SEG_LED_show_num(lcd_p[3], now_ms%10);
        }
    my_lcd_refresh();
}


typedef enum {
    TESTER_STATE_IDLE = 0,  // 系统空闲，显示成绩，显示蓝灯
    TESTER_STATE_WAITTING,  // 正在进行测试，显示红灯，等待变绿
    TESTER_STATE_COUNTING,  // 亮起红灯，开始计时

    TESTER_STATE_TOO_SOON,  // 过早按下按键，闪烁蓝灯
    TESTER_STATE_TOO_SLOW,  // 过晚按下按键，回到空闲
} TESTER_STATE_e;

TESTER_STATE_e tester_status;

void subscriber_cb_tester(void *param){ // 按下按键触发该订阅回调，处理按键
    switch(tester_status){
        case TESTER_STATE_IDLE:
            tester_status = TESTER_STATE_WAITTING;
            // 按下按键，进入测试
            // lcd 清空显示
            my_lcd_clean_all();
            for(uint8_t i = 0; i < 4; i ++){
                lcd_p[i]->write_seg_pin(lcd_p[i], SEG_LED_SEGMENT_G, 0);
            }
            my_lcd_refresh();
            
            // 关闭蓝灯闪烁，亮起红灯
            LED_B_BLINK(LED_BLINK_OFF);
            LED_G(LED_OFF);
            LED_B(LED_OFF);
            LED_R(LED_ON);
            
            // 设置随机时间后变绿闹钟
            rtx_Alarm_set_count(&alarm_tester, 2025 + 29*(rtx_Sys_get_tick()%100) - ((rtx_Sys_get_tick()/100)%10)); // 一千种情况
            rtx_Alarm_add(&alarm_tester);

            break;
            
        case TESTER_STATE_WAITTING:
            tester_status = TESTER_STATE_TOO_SOON;
            // 还未亮绿灯就按下按键，闪烁蓝灯，取消闹钟
            // 闪烁蓝灯
            LED_R(LED_OFF);
            LED_G(LED_OFF);
            LED_B_BLINK(LED_BLINK_ON);

            // 取消闹钟
            rtx_Alarm_remove(&alarm_tester);

            break;
            
        case TESTER_STATE_COUNTING:
            tester_status = TESTER_STATE_IDLE;
            // 在超时时间内按下按键

            // 关闭实时反应时间显示
            rtx_Timer_remove(&task_num_flow.timer);

            // 亮蓝灯
            LED_B_BLINK(LED_BLINK_OFF);
            LED_R(LED_OFF);
            LED_G(LED_OFF);
            LED_B(LED_ON);

            // 显示反应时间
            tester.click_ms -= tester.triger_ms;
            LOG_FMT("Time: %d.%03dms\n", tester.click_ms, tester.click_us);

            my_lcd_clean_all();
            if(tester.click_ms < 10){
                SEG_LED_show_num(lcd_p[0], tester.click_ms);
                SEG_LED_show_dot(lcd_p[0], 1);
                SEG_LED_show_num(lcd_p[1], tester.click_us/100);
                SEG_LED_show_num(lcd_p[2], (tester.click_us/10)%10);
                SEG_LED_show_num(lcd_p[3], tester.click_us%10);
            }else if(tester.click_ms < 100){
                SEG_LED_show_num(lcd_p[0], tester.click_ms/10);
                SEG_LED_show_num(lcd_p[1], tester.click_ms%10);
                SEG_LED_show_dot(lcd_p[1], 1);
                SEG_LED_show_num(lcd_p[2], tester.click_us/100);
                SEG_LED_show_num(lcd_p[3], (tester.click_us/10)%10);
            }else if(tester.click_ms < 1000){
                SEG_LED_show_num(lcd_p[0], tester.click_ms/100);
                SEG_LED_show_num(lcd_p[1], (tester.click_ms/10)%10);
                SEG_LED_show_num(lcd_p[2], tester.click_ms%10);
                SEG_LED_show_dot(lcd_p[2], 1);
                SEG_LED_show_num(lcd_p[3], tester.click_us/100);
            }else {
                SEG_LED_show_num(lcd_p[0], tester.click_ms/1000);
                SEG_LED_show_num(lcd_p[1], (tester.click_ms/100)%10);
                SEG_LED_show_num(lcd_p[2], (tester.click_ms/10)%10);
                SEG_LED_show_num(lcd_p[3], tester.click_ms%10);
            }
            my_lcd_refresh();
            
            // 取消超时闹钟
            rtx_Alarm_remove(&alarm_tester);

            break;

        case TESTER_STATE_TOO_SLOW:
        case TESTER_STATE_TOO_SOON:
            tester_status = TESTER_STATE_IDLE;
            LED_B_BLINK(LED_BLINK_OFF);
            LED_R(LED_OFF);
            LED_G(LED_OFF);
            LED_B(LED_ON);

            // 关闭实时反应时间显示
            rtx_Timer_remove(&task_num_flow.timer);

            my_lcd_clean_all();

            SEG_LED_show_num(&lcd_p1, SEG_LED_NUM_7);
            lcd_p2.write_seg_pin(&lcd_p2, SEG_LED_SEGMENT_A, 0);
            lcd_p2.write_seg_pin(&lcd_p2, SEG_LED_SEGMENT_E, 0);
            lcd_p2.write_seg_pin(&lcd_p2, SEG_LED_SEGMENT_F, 0);
            SEG_LED_show_num(&lcd_p3, SEG_LED_NUM_1);
            SEG_LED_show_num(&lcd_p4, SEG_LED_NUM_8);
            lcd_p2.write_seg_pin(&lcd_p4, SEG_LED_SEGMENT_A, 1);
            lcd_p2.write_seg_pin(&lcd_p4, SEG_LED_SEGMENT_D, 1);

            my_lcd_refresh();

            break;

        default:

            break;
    }
}

void alarm_cb_tester(void *param){
    switch(tester_status){
        case TESTER_STATE_WAITTING:
            // 闹钟到时，开始记录反应时间
            // 对齐 systick
            SysTick->VAL = 0;
            LED_B(LED_OFF);
            LED_B_BLINK(LED_BLINK_OFF);
            // 开始计时
            tester.triger_ms = rtx_Sys_get_tick();
            // 绿灯亮起
            // LED_R(LED_OFF);
            // LED_G(LED_ON);

            // 开启实时反应时间显示
            rtx_Timer_add(&task_num_flow.timer);

            GPIOA->BSRR = GPIO_PIN_6; // 红灯灭
            // 对齐 systick
            SysTick->VAL = 0;
            GPIOA->BRR = GPIO_PIN_15; // 绿灯亮

            // 设置超时时间
            rtx_Alarm_set_count(&alarm_tester, 9999);
            rtx_Alarm_add(&alarm_tester);
            tester_status = TESTER_STATE_COUNTING;

            break;

        case TESTER_STATE_COUNTING:
            // 超时未按下

            // 关闭实时反应时间显示
            rtx_Timer_remove(&task_num_flow.timer);

            // 显示 9999
            my_lcd_clean_all();
            for(uint8_t i = 0; i < 4; i ++){
                SEG_LED_show_num(lcd_p[i], 9);
            }
            my_lcd_refresh();

            // 闪烁蓝灯
            LED_R(LED_OFF);
            LED_G(LED_OFF);
            LED_B_BLINK(LED_BLINK_ON);
            tester_status = TESTER_STATE_TOO_SLOW;

            break;

        default:

            break;
    }
}


void subscriber_cb_sleep(void *param){ // 按下按键触发该订阅回调，重置休眠计时

    rtx_Alarm_set_count(&alarm_sleep, 30000);
    rtx_Alarm_add(&alarm_sleep);
}

void alarm_cb_sleep(void *param){ // 一段时间未按下按键
    // 进入深度休眠
    
    // 关灯
    LED_G(LED_OFF);
    LED_B(LED_OFF);
    LED_R(LED_OFF);
    LED_B_BLINK(LED_BLINK_OFF);
    
    // 清空显示
    my_lcd_clean_all();
    my_lcd_refresh();

    // 关闭所有外设
    HAL_LCD_DeInit(&LCD_Handle);
    
    HAL_GPIO_DeInit(GPIOA, GPIO_PIN_6 | GPIO_PIN_7 | GPIO_PIN_15);

    // 进入深度休眠
    HAL_SuspendTick();
    HAL_PWR_EnterSTOPMode(PWR_LOWPOWERREGULATOR_ON, PWR_STOPENTRY_WFI);
    HAL_ResumeTick();

    // 重启设备
    HAL_NVIC_SystemReset();

    LED_B(LED_ON);

    my_lcd_clean_all();
        SEG_LED_show_num(&lcd_p1, SEG_LED_NUM_A);
    my_lcd_refresh();

    HAL_Delay(500);
}
